#coding:utf-8

import Config;
import wx;
import os;
import wx.lib.rcsizer as rcs;
import wx.lib.intctrl;
import Global;
import Loading;
import string;
import ELog;
import traceback;
import array;
import time;
import numpy;  
import matplotlib;
import matplotlib.figure;
import matplotlib.backends.backend_wxagg;
import matplotlib.backends.backend_wx;
from mpl_toolkits.axes_grid1.axes_divider import make_axes_area_auto_adjustable
from matplotlib import rcParams
rcParams['font.family'] = 'sans-serif'
rcParams['font.sans-serif'] = ['Tahoma']
rcParams['font.size'] = '8'



try:
    from agw import fourwaysplitter as FWS
except ImportError: # if it's not there locally, try the wxPython lib.
    try:
        import wx.lib.agw.fourwaysplitter as FWS
    except ImportError:
        exit()

#菜单ID
from AppIds import *

import SerialUtil
import wx.lib.newevent

#Frame start
SERIAL_GENIUS_FS_CHAR=0x0F;
#Slash
SERIAL_GENIUS_SL_CHAR=0x1F;



#变量跟踪
class Variabletrack(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, style=wx.BORDER_DOUBLE);

        ############# 状态信息 ############
        #该模块是否启用
        self.isUsing=False;

        ############# 配置信息 ############
        self.dataBuffer=[];
        #已经存在的数据源字典
        # INT8U-0 : dataTrack index
        self.dataTrackDict={};
        #已经存在的数据源
        self.dataTrack=[];
        #X时间轴
        self.dataT=[];
        #是否显示
        self.dataShow=[];
        #图形句柄
        self.dataAxes=[];
        #自动刷新
        self.autoScale=True;
        #数据是否已经改变
        self.dataChanged=False
        #是否清除数据
        self.dataCleared=False
        
        self.dataAddingSignal = 1
        
        self.refreshTimer = wx.Timer(self);
        self.Bind(wx.EVT_TIMER, self.PlotData);
        self.refreshTimer.Start(500)
        
        # 命令解析状态
        # 0 无
        # 1 INT8U
        # 2 INT8S
        # 3 INT16U
        # 4 INT16S
        # 5 INT32U
        # 6 INT32S
        self.dataParseCurStatus=0;
        self.dataparseCurLength=0;
        
        ############# 开始布局 ###########
        gridSizer = rcs.RowColSizer();
        rowTotal=4;
        colTotal=3;

        #标题
        title=wx.StaticText(self, -1, u"变量跟踪");
        title.SetFont(wx.Font(8, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD ));
        gridSizer.Add(title, pos=(0,0), size=(1, colTotal), flag=wx.EXPAND|wx.ALIGN_CENTER_VERTICAL);

        #绘图区
        self.figure=matplotlib.figure.Figure(figsize=(1,1));
        self.figure.subplots_adjust(left=0.00, bottom=0.00, right=1.00, top=1.00, wspace=None, hspace=None);
        self.axes=self.figure.add_subplot(111);
        self.canvas = matplotlib.backends.backend_wxagg.FigureCanvasWxAgg(self, 20, self.figure);
        self.canvas.mpl_connect('button_press_event', self.on_button_press_event);    
        gridSizer.Add(self.canvas, pos=(1,0), size=(1, colTotal), flag=wx.EXPAND|wx.ALIGN_CENTER_VERTICAL);
        make_axes_area_auto_adjustable(self.axes);
        self.axes.grid(True);
        
        #清空
        btn = wx.Button(self, -1, u"清空", size=(40,35))
        self.Bind(wx.EVT_BUTTON, self.OnClearData, btn);
        gridSizer.Add(btn, pos=(2, 0), size=(1,1), flag=wx.ALIGN_CENTER_VERTICAL);
        
        #数据
        btn = wx.Button(self, -1, u"数据", size=(40,35))
        self.Bind(wx.EVT_BUTTON, self.OnSelectData, btn);
        gridSizer.Add(btn, pos=(2, 1), size=(1,1), flag=wx.ALIGN_CENTER_VERTICAL);
        
        #工具条
        self.toolbar = matplotlib.backends.backend_wx.NavigationToolbar2Wx(self.canvas);
        self.toolbar.Realize()
        # On Windows platform, default window size is incorrect, so set
        # toolbar width to figure width.
        #tw, th = self.toolbar.GetSizeTuple()
        #fw, fh = self.canvas.GetSizeTuple()
        # By adding toolbar in sizer, we are able to put it at the bottom
        # of the frame - so appearance is closer to GTK version.
        # As noted above, doesn't work for Mac.
        #self.toolbar.SetSize(wx.Size(fw, th))
        #self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
        # update the axes menu on the toolbar
        gridSizer.Add(self.toolbar, pos=(2, 2), size=(1,colTotal-2), flag=wx.EXPAND|wx.ALIGN_CENTER_VERTICAL);
        #self.toolbar.update()

        #设置变宽信息
        gridSizer.AddGrowableCol(2);
        gridSizer.AddGrowableRow(1);


        ############# 结束布局 ###########
        self.SetSizer(gridSizer);
        self.SetAutoLayout(True);
        
    #电机鼠标事件
    def on_button_press_event(self, event):
        if 'PAN'==self.axes.get_navigate_mode() or 'ZOOM'==self.axes.get_navigate_mode():
            self.autoScale=False;
        else:
            self.autoScale=True;
    
    #添加一个数据到数据跟踪
    def AddData(self, cmd, index, data):
        if cmd==0x07:
            cmdStr='INT8U-'+str(index);
        elif cmd==0x08:
            cmdStr='INT8S-'+str(index);
        elif cmd==0x09:
            cmdStr='INT16U-'+str(index);
        elif cmd==0x0A:
            cmdStr='INT16S-'+str(index);
        elif cmd==0x0B:
            cmdStr='INT32U-'+str(index);
        elif cmd==0x0C:
            cmdStr='INT32S-'+str(index);
        else:
            return
        
        self.dataAddingSignal -= 1
        while self.dataAddingSignal < 0:
            time.sleep(0.01)        
        
        if cmdStr in self.dataTrackDict:
            index=self.dataTrackDict.get(cmdStr)
        else:
            self.dataShow.append(True)
            self.dataT.append([])
            self.dataTrack.append([])
            self.dataAxes.append(None)
            
            index=len(self.dataShow)-1;
            self.dataTrackDict[cmdStr]=index;
            self.dataAxes[index], = self.axes.plot([], []);#, label=cmdStr);
        
        self.dataTrack[index].append(data)
        self.dataT[index].append(len(self.dataT[index]))
        self.dataAddingSignal  += 1
        self.dataChanged=True
    
    #绘制选定的图形到界面
    def PlotData(self, evt=None):       
        
        if not self.dataChanged:
            return
        
        self.dataAddingSignal -= 1
        if self.dataAddingSignal < 0:
            self.dataAddingSignal += 1
            return
        
        self.dataChanged=False  
        
        if self.dataCleared:
            self.axes.clear()
            self.dataCleared=False
            self.dataTrackDict.clear()
            del self.dataTrack[:]
            del self.dataT[:]
            del self.dataShow[:]
            del self.dataAxes[:]
            
        tMax=1;
        yMin=0;
        yMax=1;
        hasData=False;
        legends =[]
        
        for key,index in self.dataTrackDict.items():
            if self.dataShow[index]:
                hasData=True
                if self.dataAxes[index]:
                    if len(self.dataT[index])!=len(self.dataTrack[index]):
                        continue
                        
                    self.dataAxes[index].set_data(self.dataT[index], self.dataTrack[index])
                    self.dataAxes[index].set_label(key)
                    legends.append(key)
    
                    if self.autoScale and len(self.dataT[index])>0:
                        
                        tlen1=len(self.dataT[index])
                        if tMax<tlen1:
                            tMax=tlen1
                            
                        ymin1=min(self.dataTrack[index])
                        if yMin>ymin1:
                            yMin=ymin1
                            
                        ymax1=max(self.dataTrack[index]);
                        if yMax<ymax1:
                            yMax=ymax1
            else:
                
                self.dataAxes[index].set_data([], []);
                self.dataAxes[index].set_label('_nolegend_');
                
        if self.autoScale:       
            self.axes.set_xlim(0, tMax+1)
            self.axes.set_ylim(yMin-1, yMax+1);
        
        if hasData:
            self.axes.legend(legends)
        else:
            self.axes.legend(('None',))
        
        try:
            self.canvas.draw()
        except:
            pass
        
        self.dataAddingSignal  += 1
        
    #获取数据部分中下一个数据（如果转义自动去除转义符号）
    def GetNextDataByte(self):
        if self.dataBuffer[0]==SERIAL_GENIUS_SL_CHAR:
            self.dataBuffer.pop(0)
        return self.dataBuffer.pop(0)
        
    #新增串口数据，被串口接收所调用
    def RecvData(self, data):
        self.dataBuffer.extend(data);
        '''
        f=open('a.txt','a');
        for i in range(0,len(data)):
            f.write('%02X ' % data[i]);
        f.close();
        '''
         #解析数据
        while (self.dataParseCurStatus==0 and len(self.dataBuffer)>=5) or (self.dataParseCurStatus!=0 and len(self.dataBuffer)>=self.dataparseCurLength):
            try:
                if self.dataParseCurStatus==0:
                    
                    #找到帧头
                    while len(self.dataBuffer)>1:
                        if self.dataBuffer[0]==SERIAL_GENIUS_FS_CHAR:
                            break;
                        if self.dataBuffer[0]==SERIAL_GENIUS_SL_CHAR:
                            self.dataBuffer.pop(0);
                        self.dataBuffer.pop(0);
                    
                    if len(self.dataBuffer)<5:
                        break;
                    
                    # 0F 命令 长度 校验 数据...
                    #无
                    if self.dataBuffer[0]==SERIAL_GENIUS_FS_CHAR:
                        if 0x07<=self.dataBuffer[1]<=0x0C:
                            if self.dataBuffer[3]==self.dataBuffer[1]^self.dataBuffer[2]:
                                self.dataParseCurStatus=self.dataBuffer[1];
                                self.dataparseCurLength=self.dataBuffer[2];
                                
                                self.dataBuffer.pop(0);
                                self.dataBuffer.pop(0);
                                self.dataBuffer.pop(0);
                                self.dataBuffer.pop(0);
                            else:
                                #数据校验出错
                                self.dataBuffer.pop(0);
                                self.dataBuffer.pop(0);
                                self.dataBuffer.pop(0);
                                self.dataBuffer.pop(0);
                        else:
                            #不是我们的数据
                            self.dataBuffer.pop(0);
                            self.dataBuffer.pop(0);
                            self.dataBuffer.pop(0);
                            self.dataBuffer.pop(0);
                    else:
                        #不是一个帧头，在这里忽略
                        self.dataBuffer.pop(0);
                        
                elif self.dataParseCurStatus==0x07:
                    self.dataParseCurStatus=0; 
                    
                    item=self.GetNextDataByte();
                    value=self.GetNextDataByte();
                    
                    if 0<=item<=255:
                        self.AddData(0x07, item, value);
                        
                    
                elif self.dataParseCurStatus==0x08:
                    self.dataParseCurStatus=0;
                    
                    #INT8S
                    item=self.GetNextDataByte();
                    value=self.GetNextDataByte();
                    if value>127:
                        value=value-0x100;
                    if 0<=item<=255:
                        self.AddData(0x08, item, value);
                    
                
                elif self.dataParseCurStatus==0x09:
                    self.dataParseCurStatus=0;
                    
                    #INT16U
                    item=self.GetNextDataByte();
                    valueH=self.GetNextDataByte();
                    valueL=self.GetNextDataByte();
                    value=(valueH<<8)|valueL;
                    
                    if 0<=item<=255:
                        self.AddData(0x09, item, value);
                        
                
                elif self.dataParseCurStatus==0x0A:
                    self.dataParseCurStatus=0;
                    
                    #INT16S
                    item=self.GetNextDataByte();
                    valueH=self.GetNextDataByte();
                    valueL=self.GetNextDataByte();
                    value=(valueH<<8)|valueL;
                    if value>0x7FFF:
                        value=value-0x10000;
                        
                    if 0<=item<=255:
                        self.AddData(0x0A, item, value);
                        
                
                elif self.dataParseCurStatus==0x0B:
                    self.dataParseCurStatus=0;
                   
                    #INT32U
                    item=self.GetNextDataByte();
                    valueHH=self.GetNextDataByte();
                    valueHL=self.GetNextDataByte();
                    valueLH=self.GetNextDataByte();
                    valueLL=self.GetNextDataByte();
                    value=(valueHH<<24)|(valueHL<<16)|(valueLH<<8)|valueLL;
                    
                    if 0<=item<=255:
                        self.AddData(0x0B, item, value);
                        
                
                elif self.dataParseCurStatus==0x0C:
                    self.dataParseCurStatus=0;
                    
                    #INT32S
                    item=self.GetNextDataByte();
                    valueHH=self.GetNextDataByte();
                    valueHL=self.GetNextDataByte();
                    valueLH=self.GetNextDataByte();
                    valueLL=self.GetNextDataByte();
                    value=(valueHH<<24)|(valueHL<<16)|(valueLH<<8)|valueLL;
                    if value>0x7FFFFFFF:
                        value=value-0x100000000;
                        
                    if 0<=item<=255:
                        self.AddData(0x0C, item, value);
                                     
                else:
                    self.dataParseCurStatus=0;
                
            except:
                self.dataParseCurStatus=0;
                break;
    
    #清空数据
    def OnClearData(self, event):
        self.dataCleared = True
        self.dataChanged = True

    #选择数据
    def OnSelectData(self, event):
        # 调试用作输出数据使用
        '''
        print "\n=======================self.dataTrackDict========================\n"
        print self.dataTrackDict
        print "\n=======================self.dataTrack========================\n"
        print self.dataTrack
        print "\n=======================self.dataT========================\n"
        print self.dataT
        print "\n=======================self.dataShow========================\n"
        print self.dataShow
        print "\n=======================self.dataAxes========================\n"
        print self.dataAxes     
        return 
        '''
        lst = []
        lstSel =[]
        for key,index in self.dataTrackDict.items():
            lst.append(key);
            if self.dataShow[index]:
                lstSel.append(index);
        
        dlg = wx.MultiChoiceDialog( self, u"选择需要显示的数据", u"已接收到的数据跟踪源", lst)
        dlg.SetSelections(lstSel);
        
        if (dlg.ShowModal() == wx.ID_OK):
            selections = dlg.GetSelections();
            for index in range(0, len(self.dataShow)):
                self.dataShow[index]=False;
            for index in selections:
                self.dataShow[index]=True;
            self.dataChanged=True;
                
        dlg.Destroy();
        #重新绘图
        self.PlotData();

    #重绘函数
    def OnPaint(self, event):
        self.canvas.draw()


